<template>
    <div class="scale-container">
        <div class="scale-label">{{ distanceLabel || '超出范围' }}</div>
        <div
            v-if="barWidth"
            class="scale-bar"
            :style="{ width: barWidth + 'px' }"></div>
    </div>
</template>

<script setup lang="ts">
import { onMounted } from 'vue'
import { ref } from 'vue'

const barWidth = ref<number | undefined>(0)

const distanceLabel = ref<string | undefined>('')

const props = defineProps<{
    map: Cesium.Viewer
}>()

function cesiumScale() {
    var geodesic = new Cesium.EllipsoidGeodesic()
    var distances = [
        1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 500, 1000, 2000, 3000, 5000,
        10000, 20000, 30000, 50000, 100000, 200000, 300000, 500000, 1000000,
        2000000, 3000000, 5000000, 10000000, 20000000, 30000000, 50000000,
    ]
    // Find the distance between two pixels at the bottom center of the screen.
    let scene = viewer.scene
    let width = scene.canvas.clientWidth
    let height = scene.canvas.clientHeight

    let left = scene.camera.getPickRay(
        new Cesium.Cartesian2((width / 2) | 0, height - 1),
    )
    let right = scene.camera.getPickRay(
        new Cesium.Cartesian2((1 + width / 2) | 0, height - 1),
    )

    let globe = scene.globe
    let leftPosition = globe.pick(left, scene)
    let rightPosition = globe.pick(right, scene)

    if (!Cesium.defined(leftPosition) || !Cesium.defined(rightPosition)) {
        barWidth.value = undefined
        distanceLabel.value = undefined
        return
    }

    let leftCartographic = globe.ellipsoid.cartesianToCartographic(leftPosition)
    let rightCartographic =
        globe.ellipsoid.cartesianToCartographic(rightPosition)

    geodesic.setEndPoints(leftCartographic, rightCartographic)
    let pixelDistance = geodesic.surfaceDistance

    // Find the first distance that makes the scale bar less than 100 pixels.
    let maxBarWidth = 100
    let distance
    for (
        let i = distances.length - 1;
        !Cesium.defined(distance) && i >= 0;
        --i
    ) {
        if (distances[i] / pixelDistance < maxBarWidth) {
            distance = distances[i]
        }
    }

    if (Cesium.defined(distance) && distance) {
        var label =
            distance >= 1000
                ? (distance / 1000).toString() + ' km'
                : distance.toString() + ' m'
        barWidth.value = (distance / pixelDistance) | 0
        distanceLabel.value = label
    } else {
        barWidth.value = undefined
        distanceLabel.value = undefined
    }
}

let viewer: Cesium.Viewer

onMounted(() => {
    viewer = props.map

    viewer.scene.postRender.addEventListener(function () {
        cesiumScale()
    })
})
</script>

<style lang="scss" scoped>
@use '/src/assets/scss/main.scss' as *;
.template-container {
    width: 100%;
    height: 100%;
    position: relative;
}
.cesium-container {
    width: 100%;
    height: 100%;
}
.scale-container {
    position: absolute;
    z-index: 20;
    right: 80px;
    bottom: 10px;
    width: 120px;
    height: 40px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: $c-gray-10;
    border: 1px solid $c-gray-8;
    border-radius: 4px;
    box-sizing: border-box;
}
.scale-label {
    font-size: 12px;
    color: #fff;
    text-align: center;
}
.scale-bar {
    transition: width 0.3s;
    position: relative;
    padding-top: 10px;
}
.scale-bar::after {
    content: '';
    position: absolute;
    width: 100%;
    height: 10px;
    border: 1px solid #fff;
    border-top: none;
    left: 0;
    bottom: 0;
}
</style>
